using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using OpenComposite.Base.Collections;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.Designer.BObjects;
using OpenComposite.EII.Designer.BUSView;
using OpenComposite.EII.Forms;
using System.Collections.ObjectModel;

namespace OpenComposite.EII.Repository
{
	[RepositoryItem(ItemType.BObject, "business_objects", "bobj_id")]
	public class BusinessObject : RepositoryItemBaseEx
	{
		#region Initialization
		/// <summary>
		/// Initializes a new instance of the <see cref="BusinessObject"/> class.
		/// </summary>
		public BusinessObject()
			: base("bobj_id", "bobj_nm", "bobj_desc", "bobj_ntext", Resources.sNewBObject)
		{
			_schema = null;
			_symbol = null;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="BusinessObject"/> class.
		/// </summary>
		/// <param name="bCreateNew">if set to <c>true</c> [b create new].</param>
		public BusinessObject(bool bCreateNew)
			: this()
		{
			if ( bCreateNew )
				this.CreateNew();
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="BusinessObject"/> class.
		/// </summary>
		/// <param name="id">The ID.</param>
		public BusinessObject(int id)
			: this()
		{
			this.Load(id);
		}
		#endregion

		#region Properties

		private BusinessObjectFieldCollection _fields = null;
		/// <summary>
		/// Gets the business object fields.
		/// </summary>
		/// <value>The business object fields.</value>
		public BusinessObjectFieldCollection BusinessObjectFields
		{
			get
			{
				if ( _fields == null ) {
					_dtFields = Global.Data.GetBusinessObjectItems(this.ID);
					_fields = new BusinessObjectFieldCollection(this, _dtFields);
					_fields.CollectionChanged += new CollectionChangeEventHandler(_fields_CollectionChanged);
				}
				return _fields;
			}
		}

		private XmlSchema _schema;
		/// <summary>
		/// Gets or sets the schema.
		/// </summary>
		/// <value>The schema.</value>
		[Editor(typeof(CodeEditorUI), typeof(UITypeEditor))]
		public XmlSchema Schema
		{
			get
			{
				generateXmlSchema();
				if ( _schema == null )
					_schema = getSchema("bobj_schema");
				return _schema;
			}
			set
			{
				_schema = value;
				setSchema("Schema", "bobj_schema", _schema);
			}
		}
		public XmlQualifiedName XmlQualifiedName
		{
			get { return new XmlQualifiedName(this.Name, "http://www.OpenComposite.com/canonical_document"); }
		}
		/// <summary>
		/// Gets the schema string.
		/// </summary>
		/// <value>The schema string.</value>
		public string SchemaString
		{
			get
			{
				generateXmlSchema();
				return getString("bobj_schema", null);
			}
		}

		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public override string ImageKey
		{
			get { return "bobject"; }
		}
		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public override string SelectedImageKey
		{
			get { return "bobject"; }
		}
		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public override Image Image
		{
			get { return Resources.bobject; }
		}
		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public override Image SelectedImage
		{
			get { return this.Image; }
		}

		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public override ItemType RepositoryItemType
		{
			get { return ItemType.BObject; }
		}
		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public override string RepositoryItemTypeName
		{
			get { return Resources.sBObject; }
		}
		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public override string RepositoryItemTypeDescription
		{
			get { return ""; }
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public override string TableName
		{
			get { return "business_objects"; }
		}
		private static List<ItemType> _LISTALLOWED = new List<ItemType>();
		//new ItemType[] { ItemType.BObject, ItemType.GenericFolder });
		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public override List<ItemType> AllowedChildTypes
		{
			get { return _LISTALLOWED; }
		}

		private BusinessObjectSymbol _symbol;
		/// <summary>
		/// Gets or sets the symbol.
		/// </summary>
		/// <value>The symbol.</value>
		public BusinessObjectSymbol Symbol
		{
			get { return _symbol; }
			set { _symbol = value; }
		}

		/// <summary>
		/// Gets or sets the workflow field ID.
		/// </summary>
		/// <value>The workflow field ID.</value>
		public int WorkflowFieldID
		{
			get { return getInt("wf_field_id", -1); }
			set { setValue("WorkflowFieldID", "wf_field_id", value); }
		}
		/// <summary>
		/// Gets or sets the workflow field.
		/// </summary>
		/// <value>The workflow field.</value>
		public WorkflowField WorkflowField
		{
			get
			{
				WorkflowField field = null;
				if ( this.WorkflowFieldID > 0 ) {
					field = this.RepositoryService.GetItem<OpenComposite.EII.Repository.WorkflowField>(this.WorkflowFieldID);
				}
				return field;
			}
			set
			{
				if ( value != null ) {
					this.WorkflowFieldID = value.ID;
				} else {
					this.WorkflowFieldID = -1;
				}
			}
		}

		private BusinessObjectProperties _properties = null;
		/// <summary>
		/// Gets the extended properties.
		/// </summary>
		/// <value>The extended properties.</value>
		public BusinessObjectProperties ExtendedProperties
		{
			get
			{
				if ( _properties == null ) {
					_properties = getXmlSerializedObject<BusinessObjectProperties>("bobj_ntext");
					if ( _properties == null )
						_properties = new BusinessObjectProperties();
				}
				return _properties;
			}
		}
		#endregion

		#region Methods
		//override
		/// <summary>
		/// Loads the item with the specified ID.
		/// </summary>
		/// <param name="id">The ID.</param>
		/// <returns></returns>
		public override bool Load(int id)
		{
			bool bOK = base.Load(id);
			return bOK;
		}

		void _fields_CollectionChanged(object sender, CollectionChangeEventArgs e)
		{
			PropertyInfo pInfo = this.GetType().GetProperty("BusinessObjectFields");
			OnItemChanged(pInfo, e.Action, e.Element);
		}

		/// <summary>
		/// Reloads this instance.
		/// </summary>
		/// <returns><c>true</c> if successfully reloaded.</returns>
		public override bool Reload()
		{
			bool bOK = base.Reload();
			return bOK;
		}
		/// <summary>
		/// Saves this instance.
		/// </summary>
		/// <returns></returns>
		public override bool Save()
		{
			if ( _dtFields != null ) {
				DataTable dt = _dtFields.Clone();
				foreach ( BusinessObjectField f in _fields ) {
					dt.ImportRow(f.Row);
				}
				Global.Data.SetBusinessObjectItems(this.ID, dt);
			}
			if ( this.Name != Resources.sNewBObject ) {
				this.ExtendedProperties.BusinessObjectCode = this.GenerateCSharpCode();
				BindingListEx<BusinessObject> parentBos = Global.Data.GetParentBusinessObjects(this.ID);
				foreach ( BusinessObject parent in parentBos ) {
					parent.Save();
				}
			}
			if ( _properties != null )
				setXmlSerializedObject("ExtendedProperties", "bobj_ntext", _properties);
			return base.Save();
		}
		protected override void SetDefaultValues()
		{
			base.SetDefaultValues();
		}
		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public override Icon GetIcon()
		{
			Bitmap bmp = new Bitmap(this.Image);
			bmp.MakeTransparent(Color.Magenta);
			return Icon.FromHandle(bmp.GetHicon());
		}

		/// <summary>
		/// Deletes this instance.
		/// </summary>
		/// <param name="bAsk">if set to <c>true</c> show a message to ask for deleting.</param>
		/// <returns></returns>
		public override bool Delete(bool bAsk)
		{
			BindingListEx<BusinessObject> lstParentBOs = Global.Data.GetParentBusinessObjects(this.ID);
			if ( lstParentBOs.Count > 0 ) {
				string msg = "This Business Object is used in other Business Objects." +
							 Environment.NewLine + Environment.NewLine +
							 "Parent Business Objects :";
				foreach ( BusinessObject bo in lstParentBOs ) {
					msg += string.Format("{0}  {1}", Environment.NewLine, bo.Name);
				}
				msg += Environment.NewLine + Environment.NewLine + "Do you want to delete the business object?";
				DialogResult result = MessageBox.Show(msg, "Delete Business Object", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
				if ( result == DialogResult.No ) return false;

				foreach ( BusinessObject bo in lstParentBOs ) {
					for ( int i = 0; i < bo.BusinessObjectFields.Count; i++ ) {
						BusinessObjectField field = bo.BusinessObjectFields[i];
						if ( field == null ) continue;
						if ( field.BusinessObjectID == this.ID ) {
							bo.BusinessObjectFields.Remove(field);
						}
					}
					if ( bo.BusinessObjectFields.Count > 0 ) {
						bo.Save();
					}
				}
				bool bOk = base.Delete(false);
				Global.Data.DeleteRepositoryHierarchy(this);
				return bOk;
			}
			return base.Delete(bAsk);
		}

		//new
		/// <summary>
		/// Creates the new field.
		/// </summary>
		/// <returns></returns>
		public BusinessObjectField CreateNewField()
		{
			return this.BusinessObjectFields.CreateNewField();
		}

		/// <summary>
		/// Generates the XML schema element.
		/// </summary>
		/// <returns></returns>
		public XmlSchemaElement GenerateXmlSchemaElement(out List<XmlSchemaType> types)
		{
			return GenerateXmlSchemaElement(null, out types);
		}

		/// <summary>
		/// Generates the XML schema element.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="types">The types.</param>
		/// <returns></returns>
		public XmlSchemaElement GenerateXmlSchemaElement(string name, out List<XmlSchemaType> types)
		{
			if ( string.IsNullOrEmpty(name) ) name = this.Name;
			types = new List<XmlSchemaType>();

			XmlSchemaElement thisElement = new XmlSchemaElement();
			thisElement.Name = name;
			thisElement.SchemaTypeName = this.XmlQualifiedName;

			XmlSchemaComplexType complexType = new XmlSchemaComplexType();
			complexType.Name = this.Name;
			types.Add(complexType);
			XmlSchemaSequence seq = new XmlSchemaSequence();
			complexType.Particle = seq;
			if ( this.BusinessObjectFields != null ) {
				List<BusinessObjectField> removedFields = new List<BusinessObjectField>();
				foreach ( BusinessObjectField field in this.BusinessObjectFields ) {
					if ( !field.IsReference && field.Noun == null ) {
						removedFields.Add(field);
						continue;
					}
					if ( field.IsXmlAttribute ) {
						XmlSchemaAttribute attrib = new XmlSchemaAttribute();
						attrib.Name = field.Name;
						complexType.Attributes.Add(attrib);
					} else {
						XmlSchemaElement elem = new XmlSchemaElement();
						if ( !field.IsReference ) {
							elem.Name = field.Name;
							if ( field.MinOccurs != 1 )
								elem.MinOccursString = field.MinOccursString;
							if ( field.MaxOccurs != 1 )
								elem.MaxOccursString = field.MaxOccursString;
							elem.SchemaTypeName = new XmlQualifiedName(field.DataType, "http://www.w3.org/2001/XMLSchema");
						} else {
							if ( field.BusinessObject == null )
								//break; ;
								throw new NullReferenceException("field.Reference is null.");
							if ( field.IsList ) {
								// special handling if extra list object (only on element which is a list)
								if ( this.BusinessObjectFields.Count == 1 &&
									 this.Name == this.BusinessObjectFields[0].Name ) {
									// create a new element for the list of current field items
									elem.Name = field.Name;
									elem.MinOccurs = 0;
									elem.SchemaTypeName = field.BusinessObject.XmlQualifiedName;
									XmlSchemaSequence seqField = new XmlSchemaSequence();
									if ( field.BusinessObject != this ) {
										List<XmlSchemaType> subTypes;
										elem = field.BusinessObject.GenerateXmlSchemaElement(field.BusinessObject.Name, out subTypes);
										addTypeDistinct(types, subTypes);
									} else {
										if ( field.BusinessObject.Schema != null && field.BusinessObject.Schema.Items.Count > 0 )
											elem = field.BusinessObject.Schema.Items[0] as XmlSchemaElement;
									}
									if ( field.MinOccurs != 1 )
										elem.MinOccursString = field.MinOccursString;
									if ( field.MaxOccurs != 1 )
										elem.MaxOccursString = field.MaxOccursString;
								} else {
									// create a new element for the list of current field items
									elem.Name = field.Name;
									elem.MinOccurs = 0;
									//wrapper type for lists
									XmlSchemaComplexType listCt = new XmlSchemaComplexType();
									listCt.Name = field.Name;
									elem.SchemaTypeName = new XmlQualifiedName(listCt.Name, "http://www.OpenComposite.com/canonical_document");
									types.Add(listCt);
									//sequence of wrapper type
									XmlSchemaSequence listSeq = new XmlSchemaSequence();
									listCt.Particle = listSeq;
									XmlSchemaElement listElem = new XmlSchemaElement();
									//XmlSchemaSequence seqField = new XmlSchemaSequence();
									if ( field.BusinessObject != this ) {
										List<XmlSchemaType> subTypes;
										listElem = field.BusinessObject.GenerateXmlSchemaElement(null, out subTypes);
										addTypeDistinct(types, subTypes);
									} else {
										if ( field.BusinessObject.Schema != null && field.BusinessObject.Schema.Items.Count > 0 )
											listElem = field.BusinessObject.Schema.Items[0] as XmlSchemaElement;
									}
									listSeq.Items.Add(listElem);
									if ( field.MinOccurs != 1 )
										listElem.MinOccursString = field.MinOccursString;
									if ( field.MaxOccurs != 1 )
										listElem.MaxOccursString = field.MaxOccursString;
								}
							} else {
								elem = null;
								// create a simple element
								if ( field.BusinessObject != null ) {
									List<XmlSchemaType> subTypes;
									elem = field.BusinessObject.GenerateXmlSchemaElement(field.Name, out subTypes);
									addTypeDistinct(types, subTypes);
								} else {
									if ( field.BusinessObject.Schema != null && field.BusinessObject.Schema.Items.Count > 0 )
										elem = field.BusinessObject.Schema.Items[0] as XmlSchemaElement;
								}
								if ( elem != null ) {
									if ( field.MinOccurs != 1 )
										elem.MinOccursString = field.MinOccursString;
									if ( field.MaxOccurs != 1 )
										elem.MaxOccursString = field.MaxOccursString;
								}
							}
						}
						if ( elem != null )
							seq.Items.Add(elem);
					}
				}
				if ( removedFields.Count > 0 ) {
					foreach ( BusinessObjectField f in removedFields ) {
						this.BusinessObjectFields.Remove(f);
					}
					this.Save();
				}
			}
			return thisElement;
		}

		/// <summary>
		/// Adds the types of the second list to the first list, no double entries.
		/// </summary>
		/// <param name="types">The types.</param>
		/// <param name="subTypes">The types to add.</param>
		private void addTypeDistinct(List<XmlSchemaType> types, List<XmlSchemaType> subTypes)
		{
			foreach ( XmlSchemaComplexType type in subTypes ) {
				var items = from t in types
							where t.Name == type.Name
							select t;
				if ( items.Count() > 0 ) continue;
				else types.Add(type);
			}
		}
		//public XmlSchemaElement GenerateXmlSchemaElement(string name)
		//{
		//    if ( string.IsNullOrEmpty(name) ) name = this.Name;
		//    XmlSchemaElement thisElement = new XmlSchemaElement();
		//    thisElement.Name = name;
		//    XmlSchemaComplexType complexType = new XmlSchemaComplexType();
		//    thisElement.SchemaType = complexType;
		//    XmlSchemaSequence seq = new XmlSchemaSequence();
		//    complexType.Particle = seq;
		//    if ( this.BusinessObjectFields != null ) {
		//        List<BusinessObjectField> removedFields = new List<BusinessObjectField>();
		//        foreach ( BusinessObjectField field in this.BusinessObjectFields ) {
		//            if ( !field.IsReference && field.Noun == null ) {
		//                removedFields.Add(field);
		//                continue;
		//            }
		//            if ( field.IsXmlAttribute ) {
		//                XmlSchemaAttribute attrib = new XmlSchemaAttribute();
		//                attrib.Name = field.Name;
		//                complexType.Attributes.Add(attrib);
		//            } else {
		//                XmlSchemaElement elem = new XmlSchemaElement();
		//                if ( !field.IsReference ) {
		//                    elem.Name = field.Name;
		//                    if ( field.MinOccurs != 1 )
		//                        elem.MinOccursString = field.MinOccursString;
		//                    if ( field.MaxOccurs != 1 )
		//                        elem.MaxOccursString = field.MaxOccursString;
		//                    elem.SchemaTypeName = new XmlQualifiedName(field.DataType, "http://www.w3.org/2001/XMLSchema");
		//                } else {
		//                    if ( field.BusinessObject == null )
		//                        //break; ;
		//                        throw new NullReferenceException("field.Reference is null.");
		//                    if ( field.Name != field.DataType && field.MaxOccurs != 0 && field.MaxOccurs != 1 ) {
		//                        // create a new element for the list of current field items
		//                        elem.Name = field.Name;
		//                        elem.MinOccurs = 0;
		//                        XmlSchemaComplexType ctField = new XmlSchemaComplexType();
		//                        elem.SchemaType = ctField;
		//                        XmlSchemaSequence seqField = new XmlSchemaSequence();
		//                        ctField.Particle = seqField;
		//                        XmlSchemaElement elemField = null;
		//                        if ( field.BusinessObject != this ) {
		//                            elemField = field.BusinessObject.GenerateXmlSchemaElement();
		//                        } else {
		//                            if ( field.BusinessObject.Schema != null && field.BusinessObject.Schema.Items.Count > 0 )
		//                                elemField = field.BusinessObject.Schema.Items[0] as XmlSchemaElement;
		//                        }
		//                        if ( elemField != null ) {
		//                            if ( field.MinOccurs != 1 )
		//                                elemField.MinOccursString = field.MinOccursString;
		//                            if ( field.MaxOccurs != 1 )
		//                                elemField.MaxOccursString = field.MaxOccursString;
		//                            seqField.Items.Add(elemField);
		//                        }
		//                    } else {
		//                        elem = null;
		//                        // create a simple element
		//                        if ( field.BusinessObject != null ) {
		//                            elem = field.BusinessObject.GenerateXmlSchemaElement(field.Name);
		//                        } else {
		//                            if ( field.BusinessObject.Schema != null && field.BusinessObject.Schema.Items.Count > 0 )
		//                                elem = field.BusinessObject.Schema.Items[0] as XmlSchemaElement;
		//                        }
		//                        if ( elem != null ) {
		//                            if ( field.MinOccurs != 1 )
		//                                elem.MinOccursString = field.MinOccursString;
		//                            if ( field.MaxOccurs != 1 )
		//                                elem.MaxOccursString = field.MaxOccursString;
		//                        }
		//                    }
		//                }
		//                if ( elem != null )
		//                    seq.Items.Add(elem);
		//            }
		//        }
		//        if ( removedFields.Count > 0 ) {
		//            foreach ( BusinessObjectField f in removedFields ) {
		//                this.BusinessObjectFields.Remove(f);
		//            }
		//            this.Save();
		//        }
		//    }
		//    return thisElement;
		//}

		private void generateXmlSchema()
		{
			XmlSchema schema = new XmlSchema();
			List<XmlSchemaType> types;
			XmlSchemaElement root = null;
			if ( this.WorkflowField != null ) {
				if ( this.WorkflowField.BusinessObject == null ) {
					types = new List<XmlSchemaType>();
					XmlTypeCode typeCode = (XmlTypeCode)Enum.Parse(typeof(XmlTypeCode), this.WorkflowField.DataType, true);
					//XmlSchemaType type = XmlSchemaComplexType.GetBuiltInComplexType(typeCode);
					//if ( type == null ) {
					//    type = XmlSchemaSimpleType.GetBuiltInSimpleType(typeCode);
					//}
					//if ( type != null ) {
					//    types.Add(type);
					//}
					root = new XmlSchemaElement();
					root.Name = this.WorkflowField.Name;
					root.SchemaTypeName = new XmlQualifiedName(this.WorkflowField.DataType, "http://www.w3.org/2001/XMLSchema");
				} else {
					root = this.WorkflowField.BusinessObject.GenerateXmlSchemaElement(out types);
				}
			} else {
				root = this.GenerateXmlSchemaElement(out types);
			}
			schema.TargetNamespace = "http://www.OpenComposite.com/canonical_document";
			schema.Namespaces.Add("tns", "http://www.OpenComposite.com/canonical_document");
			schema.Namespaces.Add("", "http://www.OpenComposite.com/canonical_document");
			schema.AttributeFormDefault = XmlSchemaForm.Unqualified;
			schema.ElementFormDefault = XmlSchemaForm.Qualified;
			if ( root != null ) {
				schema.Items.Add(root);
			}
			foreach ( XmlSchemaType type in types ) {
				schema.Items.Add(type);
			}
			//schema.TargetNamespace = "http://www.OpenComposite.com/businessobjects/";

			this.Schema = schema;
		}

		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString()
		{
			return this.Name;
		}

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public override IRepositoryItem Copy(bool deep)
		{
			return this.CopyInternal(deep, null);
		}
		internal BusinessObject CopyInternal(bool deep, Dictionary<int, int> mapBObjsOldNew)
		{
			BusinessObject copy = new BusinessObject(true);
			copy.InitializeServiceProvider(this);
			this.CopyDataRowToTarget(copy);
			copy.BeginEdit();
			foreach ( var field in this.BusinessObjectFields ) {
				copy.BusinessObjectFields.AddCopyOf(field, deep, mapBObjsOldNew);
			}
			copy.EndEdit(true);
			return copy;
		}
		#endregion

		#region Variables
		private DataTable _dtFields;
		//private object lockThis = new object();

		#endregion

		#region Constants
		internal const string ColumnID = "bobj_id";
		internal const string ColumnName = "bobj_nm";
		internal const string ColumnDescription = "bobj_desc";
		internal const string ColumnNText = "bobj_ntext";
		#endregion

	}

	#region Class: BusinessObjectProperties
	public class BusinessObjectProperties
	{
		/// <summary>
		/// Gets or sets the business object code.
		/// </summary>
		/// <value>The business object code.</value>
		public string BusinessObjectCode { get; set; }
	}
	#endregion

	#region Class: Field
	[TypeConverter(typeof(ExpandableObjectConverter))]
	public class BusinessObjectField : DataRowItemAbstract
	{
		#region Initialization
		/// <summary>
		/// Initializes a new instance of the <see cref="BusinessObjectField"/> class.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="row">The row.</param>
		internal BusinessObjectField(IServiceProvider serviceProvider, DataRow row)
		{
			base.row = row;
			base.id = 0;
			base.name = "";
			base.colnmId = "bobj_id";
			base.colnmNm = "item_nm";
			base.colnmDesc = "";
			base.colnmNText = "";
			_serviceProvider = serviceProvider;
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the name.
		/// </summary>
		/// <value>The name.</value>
		public string Name
		{
			get
			{
				if ( this.Noun != null )
					return this.Noun.Name;
				else
					return getString("item_nm", "");
			}
			set { setValue("Name", "item_nm", value); }
		}
		/// <summary>
		/// Gets the type of the data.
		/// </summary>
		/// <value>The type of the data.</value>
		public string DataType
		{
			get
			{
				string datatype = "";
				BusinessObject bo = this.BusinessObject;
				Noun n = this.Noun;
				if ( bo != null ) {
					datatype = bo.Name;
				} else if ( n != null ) {
					datatype = n.DataType;
				}
				return datatype;
			}
		}
		/// <summary>
		/// Gets or sets the min occurs.
		/// </summary>
		/// <value>The min occurs.</value>
		public int MinOccurs
		{
			get { return getInt("item_minoccurs", 0); }
			set { setValue("MinOccurs", "item_minoccurs", value); }
		}
		/// <summary>
		/// Gets or sets the max occurs.
		/// </summary>
		/// <value>The max occurs.</value>
		public int MaxOccurs
		{
			get { return getInt("item_maxoccurs", -1); }
			set { setValue("MaxOccurs", "item_maxoccurs", value); }
		}
		/// <summary>
		/// Gets the min occurs string.
		/// </summary>
		/// <value>The min occurs string.</value>
		[XmlIgnore]
		public string MinOccursString
		{
			get
			{
				int minOccurs = this.MinOccurs;
				return minOccurs == -1 ? BusinessObjectField.Unbounded : minOccurs.ToString();
			}
		}
		/// <summary>
		/// Gets the max occurs string.
		/// </summary>
		/// <value>The max occurs string.</value>
		[XmlIgnore]
		public string MaxOccursString
		{
			get
			{
				int maxOccurs = this.MaxOccurs;
				return maxOccurs == -1 ? BusinessObjectField.Unbounded : maxOccurs.ToString();
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is XML attribute.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is XML attribute; otherwise, <c>false</c>.
		/// </value>
		public bool IsXmlAttribute
		{
			get { return getBool("item_is_attribute", false); }
			set { setValue("IsXmlAttribute", "item_is_attribute", value); }
		}
		/// <summary>
		/// Gets a value indicating whether this instance is reference.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is reference; otherwise, <c>false</c>.
		/// </value>
		public bool IsReference
		{
			get { return ( this.BusinessObjectID > 0 ); }
		}

		/// <summary>
		/// Gets or sets the business object.
		/// </summary>
		/// <value>The business object.</value>
		[XmlIgnore]
		public BusinessObject BusinessObject
		{
			get
			{
				if ( this.BusinessObjectID > 0 )
					return this.RepositoryService.GetItem(ItemType.BObject, this.BusinessObjectID, false) as BusinessObject;
				else
					return null;
			}
			set
			{
				if ( value != null )
					this.BusinessObjectID = value.ID;
				else
					this.BusinessObjectID = -1;
			}
		}
		/// <summary>
		/// Gets or sets the business object ID.
		/// </summary>
		/// <value>The business object ID.</value>
		public int BusinessObjectID
		{
			get { return getInt("item_bobj_id", -1); }
			set { setValue("BusinessObjectID", "item_bobj_id", value); }
		}

		/// <summary>
		/// Gets or sets the noun.
		/// </summary>
		/// <value>The noun.</value>
		[XmlIgnore]
		public Noun Noun
		{
			get
			{
				if ( this.NounID > 0 )
					return this.RepositoryService.GetItem(ItemType.Noun, this.NounID, false) as Noun;
				else
					return null;
			}
			set
			{
				if ( value != null )
					this.NounID = value.ID;
				else
					this.NounID = -1;
			}
		}
		/// <summary>
		/// Gets or sets the noun ID.
		/// </summary>
		/// <value>The noun ID.</value>
		public int NounID
		{
			get { return getInt("item_noun_id", -1); }
			set { setValue("NounID", "item_noun_id", value); }
		}

		/// <summary>
		/// Gets the unbounded.
		/// </summary>
		/// <value>The unbounded.</value>
		[XmlIgnore]
		public static string Unbounded
		{
			get { return "unbounded"; }
		}

		/// <summary>
		/// Gets the row.
		/// </summary>
		/// <value>The row.</value>
		internal DataRow Row
		{
			get { return base.row; }
		}
		private RepositoryService RepositoryService
		{
			get { return (RepositoryService)_serviceProvider.GetService(typeof(RepositoryService)); }
		}

		/// <summary>
		/// Gets a value indicating whether this instance is list.
		/// </summary>
		/// <value><c>true</c> if this instance is list; otherwise, <c>false</c>.</value>
		internal bool IsList
		{
			get { return MaxOccurs != 1; }
		}

		#endregion

		#region Variables
		private IServiceProvider _serviceProvider;
		#endregion

		/// <summary>
		/// Reloads this instance.
		/// </summary>
		/// <returns><c>true</c> if successfully reloaded.</returns>
		public override bool Reload()
		{
			// TODO: reload???
			return true;
		}
		/// <summary>
		/// Sets the default values.
		/// </summary>
		public void SetDefaultValues()
		{
			this.BusinessObjectID = -1;
			this.MinOccurs = 0;
			this.MaxOccurs = 1;
			this.Name = "";
			this.NounID = -1;
			this.IsXmlAttribute = false;
		}
		protected override bool OnItemChanging(System.Reflection.MemberInfo member, object newValue)
		{
			return true;
			// TODO: do nothing???
		}
		/// <summary>
		/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
		/// </summary>
		/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
		/// <returns>
		/// 	<c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
		/// </returns>
		/// <exception cref="T:System.NullReferenceException">
		/// The <paramref name="obj"/> parameter is null.
		/// </exception>
		public override bool Equals(object obj)
		{
			BusinessObjectField other = obj as BusinessObjectField;
			try {
				if ( other == null ) return false;
				else if ( other.NounID != this.NounID ) return false;
				else if ( other.BusinessObjectID != this.BusinessObjectID ) return false;
				else if ( other.Name != this.Name ) return false;
			} catch ( Exception ) {
				return true;
			}
			return true;
		}
		/// <summary>
		/// Returns a hash code for this instance.
		/// </summary>
		/// <returns>
		/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
		/// </returns>
		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
		protected override void OnItemChanged(System.Reflection.MemberInfo member, object oldValue, object newValue)
		{
			// TODO: do nothing???
		}
		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString()
		{
			return string.Format("{0} {1}, Min: {2}, Max: {3}", this.DataType, this.Name, this.MinOccurs, this.MaxOccurs);
		}

	}
	#endregion

	[TypeConverter(typeof(CollectionConverter))]
	public class BusinessObjectFieldCollection : ICollection<BusinessObjectField>, IList<BusinessObjectField>
	{
		#region Initialization
		/// <summary>
		/// Initializes a new instance of the <see cref="BusinessObjectFieldCollection"/> class.
		/// </summary>
		/// <param name="bobject">The bobject.</param>
		/// <param name="dtFields">The dt fields.</param>
		internal BusinessObjectFieldCollection(BusinessObject bobject, DataTable dtFields)
		{
			_dtFields = dtFields;
			_bobject = bobject;

			_fields = new List<BusinessObjectField>();

			if ( _dtFields != null )
				readFields();
		}

		private void readFields()
		{
			foreach ( DataRow row in _dtFields.Rows ) {
				_fields.Add(new BusinessObjectField(_bobject, row));
			}
		}
		#endregion

		#region Methods
		/// <summary>
		/// Creates the new field.
		/// </summary>
		/// <returns></returns>
		internal BusinessObjectField CreateNewField()
		{
			DataRow newrow = _dtFields.NewRow();
			newrow["bobj_id"] = this._bobject.ID;
			BusinessObjectField f = new BusinessObjectField(_bobject, newrow);
			f.SetDefaultValues();
			return f;
		}
		internal void AddCopyOf(BusinessObjectField fieldToCopy, bool deep,
								Dictionary<int, int> mapBObjsOldNew)
		{
			BusinessObjectField fieldCopy = this.CreateNewField();
			foreach ( DataColumn col in fieldToCopy.row.Table.Columns ) {
				if ( col.ColumnName != "bobj_id" ) {
					fieldCopy.row[col.ColumnName] = fieldToCopy.row[col.ColumnName];
				}
			}
			if ( deep ) {
				if ( fieldCopy.BusinessObject != null ) {
					BusinessObject bocopy = null;
					if ( mapBObjsOldNew != null ) {
						if ( mapBObjsOldNew.ContainsKey(fieldCopy.BusinessObjectID) ) {
							fieldCopy.BusinessObjectID = mapBObjsOldNew[fieldCopy.BusinessObjectID];
						} else {
							BusinessObject bo = fieldCopy.BusinessObject.Copy(true) as BusinessObject;
							mapBObjsOldNew.Add(fieldCopy.BusinessObjectID, bo.ID);
							fieldCopy.BusinessObjectID = bo.ID;
						}
					} else {
						bocopy = fieldCopy.BusinessObject.Copy(deep) as BusinessObject;
					}
					if ( bocopy != null ) fieldCopy.BusinessObject = bocopy;
				}
			}
		}

		/// <summary>
		/// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index.
		/// </summary>
		/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
		/// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </exception>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
		/// </exception>
		public void Insert(int index, BusinessObjectField item)
		{
			_fields.Insert(index, item);
			CollectionChangeEventHandler tmp = CollectionChanged;
			if ( tmp != null )
				tmp(this, new CollectionChangeEventArgs(CollectionChangeAction.Add, item));
		}
		/// <summary>
		/// Changes the position.
		/// </summary>
		/// <param name="item">The item.</param>
		/// <param name="newPosition">The new position.</param>
		public void ChangePosition(BusinessObjectField item, int newPosition)
		{
			if ( _fields.Remove(item) ) _fields.Insert(newPosition, item);
			CollectionChangeEventHandler tmp = CollectionChanged;
			if ( tmp != null )
				tmp(this, new CollectionChangeEventArgs(CollectionChangeAction.Refresh, item));
		}
		#endregion

		#region ICollection<Field> Members

		/// <summary>
		/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		void ICollection<BusinessObjectField>.Add(BusinessObjectField item)
		{
			this.Add(item);
		}

		/// <summary>
		/// Adds the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		/// <returns></returns>
		public bool Add(BusinessObjectField item)
		{
			//if ( mustBeNull != null ) return false;
			if ( !_fields.Contains(item) ) {
				if ( _dtFields.Rows.IndexOf(item.Row) == -1 ) {
					_dtFields.Rows.Add(item.Row);
				}
				_fields.Add(item);
				CollectionChangeEventHandler tmp = CollectionChanged;
				if ( tmp != null )
					tmp(this, new CollectionChangeEventArgs(CollectionChangeAction.Add, item));
				return true;
			}
			return false;
		}
		/// <summary>
		/// Adds the specified bobject.
		/// </summary>
		/// <param name="bobject">The bobject.</param>
		/// <returns></returns>
		public BusinessObjectField Add(BusinessObject bobject)
		{
			BusinessObjectField f = CreateNewField();
			//f.SetDefaultValues();
			f.BusinessObject = bobject;
			f.Name = bobject.Name;

			//_dtFields.Rows.Add(f.Row);
			//_dtFields.AcceptChanges();
			if ( !this.Add(f) ) return null;

			return f;
		}
		/// <summary>
		/// Adds the specified noun.
		/// </summary>
		/// <param name="noun">The noun.</param>
		/// <returns></returns>
		public BusinessObjectField Add(Noun noun)
		{
			BusinessObjectField f = CreateNewField();
			//f.SetDefaultValues();
			f.Noun = noun;
			f.Name = noun.Name;

			//_dtFields.Rows.Add(f.Row);
			//_dtFields.AcceptChanges();
			if ( !this.Add(f) ) return null;

			return f;
		}

		/// <summary>
		/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		public void Clear()
		{
			_dtFields.Clear();
			_fields.Clear();
			CollectionChangeEventHandler tmp = CollectionChanged;
			if ( tmp != null )
				tmp(this, new CollectionChangeEventArgs(CollectionChangeAction.Refresh, null));
		}

		/// <summary>
		/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
		/// </summary>
		/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <returns>
		/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
		/// </returns>
		public bool Contains(BusinessObjectField item)
		{
			return _fields.Contains(item);
		}

		/// <summary>
		/// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
		/// </summary>
		/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param>
		/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
		/// <exception cref="T:System.ArgumentNullException">
		/// 	<paramref name="array"/> is null.
		/// </exception>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="arrayIndex"/> is less than 0.
		/// </exception>
		/// <exception cref="T:System.ArgumentException">
		/// 	<paramref name="array"/> is multidimensional.
		/// -or-
		/// <paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.
		/// -or-
		/// The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.
		/// -or-
		/// Type <paramref name="T"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.
		/// </exception>
		public void CopyTo(BusinessObjectField[] array, int arrayIndex)
		{
			_fields.CopyTo(array, arrayIndex);
		}

		/// <summary>
		/// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <value></value>
		/// <returns>
		/// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </returns>
		public int Count
		{
			get { return _fields.Count; }
		}

		/// <summary>
		/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </summary>
		/// <value></value>
		/// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
		/// </returns>
		public bool IsReadOnly
		{
			get { return false; }
		}

		/// <summary>
		/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <returns>
		/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </returns>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		public bool Remove(BusinessObjectField item)
		{
			if ( item.Row.RowState == DataRowState.Detached || item.Row.RowState == DataRowState.Deleted ) return true;
			bool ok = _fields.Remove(item);
			if ( ok ) {
				item.Row.Delete();
				_dtFields.AcceptChanges();
				CollectionChangeEventHandler tmp = CollectionChanged;
				if ( tmp != null )
					tmp(this, new CollectionChangeEventArgs(CollectionChangeAction.Remove, item));
				//_dtFields.Rows.Remove(item.Row);
			}
			return ok;
		}

		#endregion

		#region IEnumerable<Field> Members

		/// <summary>
		/// Returns an enumerator that iterates through the collection.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
		/// </returns>
		public IEnumerator<BusinessObjectField> GetEnumerator()
		{
			return _fields.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		/// <summary>
		/// Returns an enumerator that iterates through a collection.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
		/// </returns>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return ( (IEnumerable)_fields ).GetEnumerator();
		}

		#endregion

		#region Variables
		private List<BusinessObjectField> _fields;
		private BusinessObject _bobject;
		private DataTable _dtFields;
		#endregion

		#region Events
		/// <summary>
		/// Occurs when [collection changed].
		/// </summary>
		public event CollectionChangeEventHandler CollectionChanged;
		#endregion

		#region IEnumerable<BusinessObjectField> Members

		/// <summary>
		/// Returns an enumerator that iterates through the collection.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
		/// </returns>
		IEnumerator<BusinessObjectField> IEnumerable<BusinessObjectField>.GetEnumerator()
		{
			return _fields.GetEnumerator();
		}

		#endregion

		#region IList<BusinessObjectField> Members

		/// <summary>
		/// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </summary>
		/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
		/// <returns>
		/// The index of <paramref name="item"/> if found in the list; otherwise, -1.
		/// </returns>
		public int IndexOf(BusinessObjectField item)
		{
			return _fields.IndexOf(item);
		}

		/// <summary>
		/// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
		/// </summary>
		/// <param name="index">The zero-based index of the item to remove.</param>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </exception>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
		/// </exception>
		public void RemoveAt(int index)
		{
			BusinessObjectField item = _fields[index];
			_fields.RemoveAt(index);
			CollectionChangeEventHandler tmp = CollectionChanged;
			if ( tmp != null )
				tmp(this, new CollectionChangeEventArgs(CollectionChangeAction.Remove, item));
		}

		/// <summary>
		/// Gets or sets the <see cref="OpenComposite.EII.Repository.BusinessObjectField"/> at the specified index.
		/// </summary>
		/// <value></value>
		public BusinessObjectField this[int index]
		{
			get { return _fields[index]; }
			set { _fields[index] = value; }
		}

		#endregion
	}

	public class NamedBusinessObject : IEquatable<NamedBusinessObject>
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="NamedBusinessObject"/> class.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="bobj">The bobj.</param>
		public NamedBusinessObject(string name, BusinessObject bobj)
		{
			this.Name = name;
			this.BusinessObject = bobj;
			this.LogicalActivity = null;
			this.WorkflowField = null;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="NamedBusinessObject"/> class.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="bobj">The bobj.</param>
		/// <param name="la">The la.</param>
		public NamedBusinessObject(string name, BusinessObject bobj, LogicalActivity la)
			: this(name, bobj)
		{
			this.LogicalActivity = la;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="NamedBusinessObject"/> class.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="bobj">The bobj.</param>
		/// <param name="wff">The WFF.</param>
		public NamedBusinessObject(string name, BusinessObject bobj, WorkflowField wff)
			: this(name, bobj)
		{
			this.WorkflowField = wff;
			if ( wff.BusinessObject == null ) this.DataType = wff.DataType;
		}
		/// <summary>
		/// Gets or sets the name.
		/// </summary>
		/// <value>The name.</value>
		public string Name { get; set; }
		/// <summary>
		/// Gets or sets the logical activity.
		/// </summary>
		/// <value>The logical activity.</value>
		public LogicalActivity LogicalActivity { get; set; }
		/// <summary>
		/// Gets or sets the workflow field.
		/// </summary>
		/// <value>The workflow field.</value>
		public WorkflowField WorkflowField { get; set; }
		/// <summary>
		/// Gets or sets the type of the data.
		/// </summary>
		/// <value>The type of the data.</value>
		public string DataType { get; set; }
		/// <summary>
		/// Gets or sets the business object.
		/// </summary>
		/// <value>The business object.</value>
		public BusinessObject BusinessObject { get; set; }
		/// <summary>
		/// Gets or sets the tag.
		/// </summary>
		/// <value>The tag.</value>
		internal object Tag { get; set; }
		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString()
		{
			return string.Format("Type = {0}, Name = {1}", BusinessObject.Name, Name);
		}

		public NamedBusinessObject Copy(bool deep)
		{
			BusinessObject bo;
			if ( deep ) {
				bo = this.BusinessObject.Copy(deep) as BusinessObject;
			} else {
				bo = this.BusinessObject;
			}
			NamedBusinessObject copy = new NamedBusinessObject(this.Name, bo);
			copy.DataType = this.DataType;
			copy.LogicalActivity = this.LogicalActivity;
			copy.Tag = this.Tag;
			copy.WorkflowField = this.WorkflowField;

			Global.Data.AddRepositoryItemToDomainFolder(Global.Status.CurrentDomainId, copy.BusinessObject);

			return copy;
		}

		#region IEquatable<NamedBusinessObject> Members

		/// <summary>
		/// Indicates whether the current object is equal to another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>
		/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
		/// </returns>
		bool IEquatable<NamedBusinessObject>.Equals(NamedBusinessObject other)
		{
			if ( other != null &&
				other.Name == this.Name &&
				other.BusinessObject == this.BusinessObject &&
				other.LogicalActivity == this.LogicalActivity ) return true;
			return false;
		}

		#endregion
	}

	public class NamedBusinessObjectCollection : IList<NamedBusinessObject>
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="NamedBusinessObjectCollection"/> class.
		/// </summary>
		public NamedBusinessObjectCollection()
		{

		}
		/// <summary>
		/// Initializes a new instance of the <see cref="NamedBusinessObjectCollection"/> class.
		/// </summary>
		/// <param name="owner">The owner.</param>
		public NamedBusinessObjectCollection(BUSDocumentSymbol owner)
		{
			_owner = owner;
		}

		protected enum CheckDuplicateType
		{
			Reference = 0,
			Name = 1,
			BusinessObject = 2
		}

		/// <summary>
		/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		public void Add(NamedBusinessObject item)
		{
			_innerList.Add(item);
			if ( _owner != null ) _owner.OnBusinessObjectAdded();
		}
		/// <summary>
		/// Adds the distinct.
		/// </summary>
		/// <param name="item">The item.</param>
		public void AddDistinct(NamedBusinessObject item)
		{
			if ( !Contains(item.Name) ) {
				_innerList.Add(item);
				if ( _owner != null ) _owner.OnBusinessObjectAdded();
			}
		}
		/// <summary>
		/// Adds the specified name.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="bobject">The bobject.</param>
		/// <param name="la">The la.</param>
		public void Add(string name, BusinessObject bobject, LogicalActivity la)
		{
			if ( bobject == null ) throw new ArgumentNullException("BusinessObject must not be null.");
			_innerList.Add(new NamedBusinessObject(name, bobject, la));
			if ( _owner != null ) _owner.OnBusinessObjectAdded();
		}
		/// <summary>
		/// Adds the range.
		/// </summary>
		/// <param name="items">The items.</param>
		public void AddRange(IList<NamedBusinessObject> items)
		{
			foreach ( NamedBusinessObject item in items ) {
				_innerList.Add(item);
				if ( _owner != null ) _owner.OnBusinessObjectAdded();
			}
		}
		/// <summary>
		/// Adds the range distinct.
		/// </summary>
		/// <param name="items">The items.</param>
		public void AddRangeDistinct(IList<NamedBusinessObject> items)
		{
			foreach ( NamedBusinessObject item in items ) {
				if ( !Contains(item.Name) ) {
					_innerList.Add(item);
				}
			}
		}
		/// <summary>
		/// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index.
		/// </summary>
		/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
		/// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </exception>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
		/// </exception>
		public void Insert(int index, NamedBusinessObject item)
		{
			_innerList.Insert(index, item);
			if ( _owner != null ) _owner.OnBusinessObjectAdded();
		}
		/// <summary>
		/// Inserts the distinct.
		/// </summary>
		/// <param name="index">The index.</param>
		/// <param name="item">The item.</param>
		public void InsertDistinct(int index, NamedBusinessObject item)
		{
			if ( !Contains(item.Name) ) Insert(index, item);
		}
		/// <summary>
		/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		public void Clear()
		{
			_innerList.Clear();
			if ( _owner != null ) _owner.OnBusinessObjectsCleared();
		}
		/// <summary>
		/// Removes the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		public void Remove(NamedBusinessObject item)
		{
			_innerList.Remove(item);
			if ( _owner != null ) _owner.OnBusinessObjectRemoved();
		}
		/// <summary>
		/// Removes the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		public void Remove(BusinessObject item)
		{
			for ( int i = 0; i < _innerList.Count; i++ ) {
				if ( this.BusinessObjects[i] == item ) {
					_innerList.RemoveAt(i);
					if ( _owner != null ) _owner.OnBusinessObjectRemoved();
				}
			}
		}
		/// <summary>
		/// Removes the specified name.
		/// </summary>
		/// <param name="name">The name.</param>
		public void Remove(string name)
		{
			for ( int i = 0; i < _innerList.Count; i++ ) {
				if ( this.Names[i] == name ) {
					_innerList.RemoveAt(i);
					if ( _owner != null ) _owner.OnBusinessObjectRemoved();
				}
			}
		}
		/// <summary>
		/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
		/// </summary>
		/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <returns>
		/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
		/// </returns>
		protected bool Contains(NamedBusinessObject item)
		{
			return _innerList.Contains(item);
		}
		/// <summary>
		/// Determines whether [contains] [the specified value].
		/// </summary>
		/// <param name="value">The value.</param>
		/// <returns>
		/// 	<c>true</c> if [contains] [the specified value]; otherwise, <c>false</c>.
		/// </returns>
		public bool Contains(string value)
		{
			foreach ( string name in this.Names ) {
				if ( name == value ) return true;
			}
			return false;
		}
		/// <summary>
		/// Determines whether [contains] [the specified value].
		/// </summary>
		/// <param name="value">The value.</param>
		/// <returns>
		/// 	<c>true</c> if [contains] [the specified value]; otherwise, <c>false</c>.
		/// </returns>
		public bool Contains(BusinessObject value)
		{
			foreach ( BusinessObject bobj in this.BusinessObjects ) {
				if ( bobj == value ) return true;
			}
			return false;
		}
		/// <summary>
		/// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </summary>
		/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
		/// <returns>
		/// The index of <paramref name="item"/> if found in the list; otherwise, -1.
		/// </returns>
		public int IndexOf(NamedBusinessObject item)
		{
			return _innerList.IndexOf(item);
		}
		/// <summary>
		/// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
		/// </summary>
		/// <param name="index">The zero-based index of the item to remove.</param>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </exception>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
		/// </exception>
		public void RemoveAt(int index)
		{
			_innerList.RemoveAt(index);
		}
		/// <summary>
		/// Copies to.
		/// </summary>
		/// <param name="array">The array.</param>
		/// <param name="index">The index.</param>
		public void CopyTo(NamedBusinessObject[] array, int index)
		{
			_innerList.CopyTo(array, index);
		}

		/// <summary>
		/// Returns an enumerator that iterates through the collection.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
		/// </returns>
		public IEnumerator<NamedBusinessObject> GetEnumerator()
		{
			return _innerList.GetEnumerator();
		}

		/// <summary>
		/// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <value></value>
		/// <returns>
		/// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </returns>
		public int Count
		{
			get { return _innerList.Count; }
		}
		/// <summary>
		/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </summary>
		/// <value></value>
		/// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
		/// </returns>
		public bool IsReadOnly
		{
			get { return false; }
		}
		/// <summary>
		/// Gets the names.
		/// </summary>
		/// <value>The names.</value>
		public IList<string> Names
		{
			get
			{
				return ( from item in _innerList
						 select item.Name ).ToList().ToList();
			}
		}
		/// <summary>
		/// Gets the business objects.
		/// </summary>
		/// <value>The business objects.</value>
		public IList<BusinessObject> BusinessObjects
		{
			get
			{
				return ( from item in _innerList
						 select item.BusinessObject ).ToList();
			}
		}
		/// <summary>
		/// Gets the logical activities.
		/// </summary>
		/// <value>The logical activities.</value>
		public IList<LogicalActivity> LogicalActivities
		{
			get
			{
				return ( from item in _innerList
						 select item.LogicalActivity ).ToList();
			}
		}

		/// <summary>
		/// Gets or sets the <see cref="OpenComposite.EII.Repository.NamedBusinessObject"/> at the specified index.
		/// </summary>
		/// <value></value>
		public NamedBusinessObject this[int index]
		{
			get { return _innerList[index]; }
			set { _innerList[index] = value; }
		}
		/// <summary>
		/// Gets the <see cref="OpenComposite.EII.Repository.BusinessObject"/> with the specified name.
		/// </summary>
		/// <value></value>
		public BusinessObject this[string name]
		{
			get
			{
				var items = from item in this.BusinessObjects
							where item.Name == name
							select item;
				if ( items.Count() > 1 ) throw new ArgumentException("Multiple entries for this key exist.");
				if ( items.Count() == 0 ) throw new ArgumentOutOfRangeException("Index is out of range.");
				return items.First();
			}
			//set {

			//}
		}

		private BindingListEx<NamedBusinessObject> _innerList = new BindingListEx<NamedBusinessObject>();
		private BUSDocumentSymbol _owner = null;

		#region IList<NamedBusinessObject> Members

		/// <summary>
		/// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </summary>
		/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
		/// <returns>
		/// The index of <paramref name="item"/> if found in the list; otherwise, -1.
		/// </returns>
		int IList<NamedBusinessObject>.IndexOf(NamedBusinessObject item)
		{
			return this.IndexOf(item);
		}

		/// <summary>
		/// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index.
		/// </summary>
		/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
		/// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </exception>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
		/// </exception>
		void IList<NamedBusinessObject>.Insert(int index, NamedBusinessObject item)
		{
			this.Insert(index, item);
		}

		/// <summary>
		/// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
		/// </summary>
		/// <param name="index">The zero-based index of the item to remove.</param>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
		/// </exception>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
		/// </exception>
		void IList<NamedBusinessObject>.RemoveAt(int index)
		{
			this.RemoveAt(index);
		}

		/// <summary>
		/// Gets or sets the <see cref="OpenComposite.EII.Repository.NamedBusinessObject"/> at the specified index.
		/// </summary>
		/// <value></value>
		NamedBusinessObject IList<NamedBusinessObject>.this[int index]
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		#endregion

		#region ICollection<NamedBusinessObject> Members

		/// <summary>
		/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		void ICollection<NamedBusinessObject>.Add(NamedBusinessObject item)
		{
			this.Add(item);
		}

		/// <summary>
		/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		void ICollection<NamedBusinessObject>.Clear()
		{
			this.Clear();
		}

		/// <summary>
		/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
		/// </summary>
		/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <returns>
		/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
		/// </returns>
		bool ICollection<NamedBusinessObject>.Contains(NamedBusinessObject item)
		{
			return this.Contains(item);
		}

		/// <summary>
		/// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
		/// </summary>
		/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param>
		/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
		/// <exception cref="T:System.ArgumentNullException">
		/// 	<paramref name="array"/> is null.
		/// </exception>
		/// <exception cref="T:System.ArgumentOutOfRangeException">
		/// 	<paramref name="arrayIndex"/> is less than 0.
		/// </exception>
		/// <exception cref="T:System.ArgumentException">
		/// 	<paramref name="array"/> is multidimensional.
		/// -or-
		/// <paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.
		/// -or-
		/// The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.
		/// -or-
		/// Type <paramref name="T"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.
		/// </exception>
		void ICollection<NamedBusinessObject>.CopyTo(NamedBusinessObject[] array, int arrayIndex)
		{
			this.CopyTo(array, arrayIndex);
		}

		/// <summary>
		/// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <value></value>
		/// <returns>
		/// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </returns>
		int ICollection<NamedBusinessObject>.Count
		{
			get { return this.Count; }
		}

		/// <summary>
		/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </summary>
		/// <value></value>
		/// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
		/// </returns>
		bool ICollection<NamedBusinessObject>.IsReadOnly
		{
			get { return this.IsReadOnly; }
		}

		/// <summary>
		/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </summary>
		/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
		/// <returns>
		/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
		/// </returns>
		/// <exception cref="T:System.NotSupportedException">
		/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
		/// </exception>
		bool ICollection<NamedBusinessObject>.Remove(NamedBusinessObject item)
		{
			this.Remove(item);
			return true;
		}

		#endregion

		#region IEnumerable<NamedBusinessObject> Members

		/// <summary>
		/// Returns an enumerator that iterates through the collection.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
		/// </returns>
		IEnumerator<NamedBusinessObject> IEnumerable<NamedBusinessObject>.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		/// <summary>
		/// Returns an enumerator that iterates through a collection.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
		/// </returns>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		#endregion

		public override string ToString()
		{
			return string.Format("Count = {0}", this.Count);
		}

		/// <summary>
		/// Ases the read only.
		/// </summary>
		/// <returns></returns>
		internal ReadOnlyCollection<NamedBusinessObject> AsReadOnly()
		{
			return new ReadOnlyCollection<NamedBusinessObject>(this);
		}
	}
}
